package com.isyscore.os.metadata.utils;

import cn.hutool.core.codec.Base64;
import org.junit.Test;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.UUID;

/**
 * @author liy
 * @date 2023-07-25 15:53
 */
public class AesUtil {
    private static final String key = "iios-Pt2UwS9358A"; // 此密钥和hub统一

    public static String encrypt(String password) throws Exception {
        SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
        Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
        byte[] iv = generateRandomByteArray(cipher.getBlockSize());
        IvParameterSpec ivParams = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParams);

        byte[] encryptedBytes = cipher.doFinal(password.getBytes(StandardCharsets.UTF_8));
        byte[] ciphertext = new byte[iv.length + encryptedBytes.length];
        System.arraycopy(iv, 0, ciphertext, 0, iv.length);
        System.arraycopy(encryptedBytes, 0, ciphertext, iv.length, encryptedBytes.length);

        return Base64.encode(ciphertext);
    }

    public static String decrypt(String ciphertext) throws Exception {
        byte[] ciphertextBytes = Base64.decode(ciphertext);
        if (ciphertextBytes.length < 16) {
           return ciphertext;
        }

        try{
            SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
            Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
            byte[] iv = new byte[cipher.getBlockSize()];
            if (cipher.getBlockSize() >= 0) System.arraycopy(ciphertextBytes, 0, iv, 0, cipher.getBlockSize());
            IvParameterSpec ivParams = new IvParameterSpec(iv);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParams);

            byte[] decryptedBytes = cipher.doFinal(ciphertextBytes, cipher.getBlockSize(), ciphertextBytes.length - cipher.getBlockSize());
            String pass = new String(decryptedBytes, StandardCharsets.UTF_8);
            //上面运行通过了不代表是一个正常的base64。这里通过检测内容是否是utf8范围内的字符来再次校验
            if (!isValidUTF8(pass)) {
                throw new IllegalArgumentException("不是一个合法的base64");
            }
            return pass;
        }catch (Exception e){
            return ciphertext;
        }

    }

    private static boolean isValidUTF8(String inputString) {
        byte[] bytes = inputString.getBytes();
        for (byte b : bytes) {
            if (!isValidUTF8Byte(b)) {
                return false;
            }
        }
        return true;
    }

    private static boolean isValidUTF8Byte(byte b) {
        return (b >= 0x00 && b <= 0x7F) ||        // 单字节编码的范围
                (b >= (byte) 0xC2 && b <= (byte) 0xDF) ||        // 双字节编码的范围
                (b >= (byte) 0xE0 && b <= (byte) 0xEF) ||        // 三字节编码的范围
                (b >= (byte) 0xF0 && b <= (byte) 0xF4);        // 四字节编码的范围
    }

    private static byte[] generateRandomByteArray(int byteSize) {
        UUID uuid = UUID.randomUUID();
        return uuid.toString().replace("-", "").substring(0, byteSize).getBytes();
    }

    @Test
    public void test() {
        String password = "clickhouse_operator_password";
        try {
//            String encrypted = encrypt(password);
//            System.out.println("Encrypted: " + encrypted);

            String decrypted = decrypt(password);
            System.out.println("Decrypted: " + decrypted);
        } catch (Exception e) {
            e.printStackTrace();
        }

//        boolean base64Valid = isValidUTF8("124f3X@#$%^&*nfXȳ+ҷ��ve��2��+{]�");
//        System.out.println(base64Valid);
    }
}
